#include <stdbool.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include "z_logger.h"
#include "z_memory.h"

static char *get_category_name(const log4c_location_info_t *loc_info, char *category_name) {
    char *p = category_name;

    char *begin = strstr(loc_info->loc_file, "/src/");
    char *end = strstr(loc_info->loc_file, ".c");

    if (NULL != begin && NULL != end) {
        int i = 0;
        char *curr = begin + 5;
        for (; curr <= end; ++i, ++curr) {
            if (*curr == '/') {
                category_name[i] = '.';
            } else {
                category_name[i] = *curr;
            }
        }
        category_name[i] = '\0';
        p += i;
    } else {
        category_name[0] = '\0';
    }

    if (NULL != loc_info->loc_function) {
        strcpy(p, loc_info->loc_function);
    } else {
        strcpy(p, "unnamed");
    }

    return category_name;
}

void log_category_location(const log4c_location_info_t *loc_info, int priority, const char *format, ...) {
    char category_name[128];
    get_category_name(loc_info, category_name);
    log4c_category_t *category = log4c_category_get(category_name);
    if (log4c_category_is_priority_enabled(category, priority)) {
        va_list va;
        va_start(va, format);
        __log4c_category_vlog(category, loc_info, priority, format, va);
        va_end(va);
    }
}

static const char *log_format_seqiot(const log4c_layout_t *layout, const log4c_logging_event_t *event) {
    struct tm tm;
    localtime_r(&event->evt_timestamp.tv_sec, &tm);

    snprintf(event->evt_buffer.buf_data, event->evt_buffer.buf_size,
             "%04d-%02d-%02d %02d:%02d:%02d.%03ld %-8s %s:%d- %s\n",
             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
             tm.tm_hour, tm.tm_min, tm.tm_sec, event->evt_timestamp.tv_usec / 1000,
             log4c_priority_to_string(event->evt_priority),
             event->evt_category, event->evt_loc->loc_line, event->evt_msg);

    return event->evt_buffer.buf_data;
}

static const log4c_layout_type_t _layout_type_seqiot = {
        "seqiot", log_format_seqiot,
};

_Bool running = true;

void _signal_handler(int sig) {
    running = false;
    log_info("terminal with signal %d/%s", sig, strsignal(sig));
}

void log_init() {
    signal(SIGINT, _signal_handler);
    signal(SIGTERM, _signal_handler);

    log4c_layout_type_set(&_layout_type_seqiot);
    log4c_init();
}

void log_fini() {
    log4c_fini();

    z_debug();
}